/*
 * @Description  :
 * @Version      : 0.1
 * @Company      : V-Think Development Team
 * @Author       : KiraVerSace@yeah.net
 * @Date         : 2022-05-20 13:20:41
 * @LastEditTime : 2023-07-18 14:31:42
 */
#ifndef __LTE_CAT1_GM5_H__
#define __LTE_CAT1_GM5_H__

#include <Arduino.h>

#include <xRingBuffer.h>    // 服务器的数据需要缓存
#include <log.h>            // 调试

struct LTEProperty
{
    /* 固有属性 */
	uint8_t  modelType[16];
	uint8_t  version[8];
	uint8_t  imei[32];			// Module
	uint8_t  iccid[32];			// SIM card

    /* 用于通知其余线程LTE模块已经初始化完毕[LTE-Cat1] */
    bool     finishInitFlag;

    /* 每次上电会变化的属性 */
    uint8_t  localIP[16];

    /* 实时属性 */
	uint8_t  networkType;		// 2=GPRS/GSM 4=4G/ 0=No Network
	uint8_t  rssi;
	bool     linkStatus;		// true=Connected false=Unconnected
};

/**
 * @brief 链路序列号
 */
enum SocketIndex
{
    SOCKET_A = 0,
    SOCKET_B,
    SOCKET_C,
};

class LTE_CAT1_GM5
{
public:
    struct LTEProperty property;

public:
    LTE_CAT1_GM5(/* args */);
    ~LTE_CAT1_GM5();

	/* 获取模块的一些固有属性 */
    bool readPropertySequence(void);

    void begin(HardwareSerial &serial, int32_t pwrEnablePin);    // [115200/8/1/NONE]

    void powerOn(void);
    void powerOff(void);

    bool save(void);                // 保存配置并重启
	bool closeSDP(void);            // 关闭套接字分发协议

    bool readCSQ(void);
    bool readNetworkType(void);     // 2G/4G
    bool readVersion(void);
    bool readIMEI(void);
    bool readICCID(void);
    bool readLocalIP(void);

    bool setSocket  (const char *protocol,
                     const char *ip,
                     const uint16_t portNum);
    bool openSocket (void);
    bool closeSocket(void);     // 关闭SOCKET BCD
    bool readSocketLinkStatus(void);

    bool     write(const uint8_t *data, uint16_t len);
    uint16_t read (uint8_t *data, const uint16_t len, uint32_t timeout);
private:
    enum ATWorkMode
    {
        AT_MODE_CMD = 0,	// Direct command in command mode
        AT_MODE_NET,		// Password#command in passthrough mode
        AT_MODE_HTTPD,
        AT_MODE_MQTT
    };
	enum ATWorkMode workMode;


    HardwareSerial *serial;
    int32_t         pwrEnablePin;

    const char CMD_PW[8] = "VTHINK#";   // NET模式下AT指令密码


    enum ATCommandIndex
    {
        AT_NULL = 0,
        AT,

        AT_S,			// 保存当前设置并重启
		AT_SDPEN_OFF,   // 套接字分发协议关闭

        AT_CSQ,			// 查询信号强度
        AT_SYSINFO,		// 查询连接制式
        AT_VER,			// 查询固件版本号
        AT_IMEI,        // 查询 IMEI
        AT_ICCID,		// 查询 ICCID
        AT_CIP,			// 查询本地 IP

        /* Network parameters */
        AT_SOCK_SET,    // 设置 Socket 参数
        AT_SOCK_ON,     // 使能 Socket 连接 [ENABLE]
        AT_SOCK_OFF,
        AT_SOCKLK,		// 查询 Socket 连接状态
    };

    struct ATCommand
    {
        enum ATCommandIndex index;
        char command[24];
        const char expectResponse[12];
        uint16_t timeout;
    };

    const struct ATCommand atCommandList[16] =
    {
        { AT_NULL,			"NULL",				    "NULL",		    1000 },
        { AT,				"AT",				    "OK",		    6000 },
        { AT_S,				"AT+S",				    "OK",		    6000 },
		{ AT_SDPEN_OFF,		"AT+SDPEN=OFF",		    "OK",		    6000 },
        { AT_CSQ,	 		"AT+CSQ?",			    "OK",		    6000 },
        { AT_SYSINFO,		"AT+SYSINFO?",		    "OK",		    6000 },
        { AT_VER, 			"AT+VER?",			    "OK",		    6000 },
        { AT_IMEI, 			"AT+IMEI?",			    "OK",		    6000 },
        { AT_ICCID,         "AT+ICCID?",            "OK",           6000 },
        { AT_CIP,	 		"AT+CIP?",			    "OK",		    6000 },
        { AT_SOCK_SET,		"AT+SOCK=%s,%s,%d",     "OK",		    6000 },
        { AT_SOCK_ON,		"AT+SOCKEN=ON",	        "OK",		    6000 },
        { AT_SOCK_OFF,		"AT+SOCKEN=OFF",	    "OK",		    6000 },
        { AT_SOCKLK,		"AT+SOCKLK?",		    "Connected",    6000 },
    };

    uint8_t checkSum(const uint8_t *pData, const uint16_t length);
    /**
     * @brief 效果:"www.usr.cn"->"7777772E7573722E636E"
     *
     * @param src
     * @param dest
     * @return 转换后的字节数
     */
    uint16_t hexToStringArray(const char *src, char *dest);
    void flushBuffer(void);
    bool handle(const enum ATCommandIndex index, const char *command);
    bool handle(const enum ATCommandIndex index);

    String   atResponse;    // 存放AT指令的响应,用于从中解析出CSQ,VER等信息
};

extern LTE_CAT1_GM5 lte;


#endif
